﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;
using System.Collections.Generic;

namespace Examples.ReusedReplicatorActivity
{
    /// <summary>
    /// Структура, описывающая этапы 
    /// </summary>
    [Serializable]
    struct Stage
    {
        public List<String> assignedTo;
        public String title;
    }


    public sealed partial class Workflow : SequentialWorkflowActivity
    {

        // Описываем порядок стадий утверждения
        private Stage[] stages = new Stage[]
        {
              new Stage() { 
                  assignedTo = new List<String> { "MYDOMAIN\\user1", "MYDOMAIN\\user2" },
                  title = "First step (stage #{0}), task #{1}"
            } ,
              new Stage() { 
                  assignedTo = new List<String> { "MYDOMAIN\\user3"},
                  title = "Second step (stage #{0}), task #{1}"
              } 
        };


        public Workflow()
        {
            InitializeComponent();
        }

        public Guid workflowId = default(System.Guid);
        public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();

        // Начальный этап. 
        private int currentStage = -1;

        // Список данных для задач. Сколько элементов - столько задач будет создано
        public List<TaskData> stageData = new List<TaskData>();

        // Счетчик незавершенных задач
        private int uncompletedTasks = -1;


        // Вычисляем новую стадию
        private void getNextStage(object sender, ConditionalEventArgs e)
        {
            currentStage++;
            if (currentStage >= stages.Length)
            {
                this.workflowProperties.Workflow.CreateHistoryEvent((int)SPWorkflowHistoryEventType.WorkflowComment, 0, null, "Info", String.Format("Stage #{0} not found, WF finished", currentStage), string.Empty);
                e.Result = false;
                return;
            }

            e.Result = true;

            // Репликатор будет использоваться в цикле - не забывать сбрасывать старые данные
            stageData.Clear();
            uncompletedTasks = 0;
            this.workflowProperties.Workflow.CreateHistoryEvent((int)SPWorkflowHistoryEventType.WorkflowComment, 0, null, "Info", String.Format("Start new stage #{0}", currentStage), string.Empty);
        }

        /// <summary>
        /// Общая иницализация репликатора
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stageActivity_Initialized(object sender, EventArgs e)
        {

            // Для каждого исполнителя создаем запись в списке данных
            foreach (String user in stages[currentStage].assignedTo)
            {
                uncompletedTasks++;

                // Добавим данные для задачи репликатору
                stageData.Add(new TaskData
                {
                    TaskNo = uncompletedTasks,
                    Title = String.Format(stages[currentStage].title, currentStage, uncompletedTasks),
                    AssignedTo = user,
                    DeleteCompletedTask = true,
                    OnCompleted = taskActivity_OnCompleted
                });
            }
            workflowProperties.Workflow.CreateHistoryEvent((int)SPWorkflowHistoryEventType.WorkflowComment, 0, null, "Info", String.Format("Parallel approval for stage #{1} started, {0} approvers found", uncompletedTasks, currentStage), string.Empty);
        }

        /// <summary>
        /// Инициализация отдельной задачи.
        /// Передаем в нее данные
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stageActivity_ChildInitialized(object sender, ReplicatorChildEventArgs e)
        {
            ((TaskActivity)e.Activity).Data = (TaskData)e.InstanceData;
            workflowProperties.Workflow.CreateHistoryEvent((int)SPWorkflowHistoryEventType.WorkflowComment, 0, null, "Info", String.Format("Create task #{0} for '{1}'", ((TaskActivity)e.Activity).Data.TaskNo, ((TaskActivity)e.Activity).Data.AssignedTo), string.Empty);
        }

        // Ф-я, которую будет вызывать дочка
        void taskActivity_OnCompleted(TaskActivity ta)
        {
            // Если есть 
            SPListItem task = null;
            if (ta.TaskId > 0)
                task = workflowProperties.TaskList.GetItemById(ta.TaskId);

            workflowProperties.Workflow.CreateHistoryEvent((int)SPWorkflowHistoryEventType.WorkflowComment, 0, null, "Info", String.Format("Callback from Task #{0} ({1})", ta.Data.TaskNo, task == null? "task is absent" : task.Title), string.Empty);
        }


        /// <summary>
        /// Код, выполняемый при завершении каждой задачи
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stageActivity_ChildCompleted(object sender, ReplicatorChildEventArgs e)
        {
            // Если задача была завершена нормально
            if (!((TaskActivity)e.Activity).IsCancelled)
            {
                // Получаем данные из задачи
                String taskResult = ((TaskActivity)e.Activity).TaskResult;
                SPUser taskExecutor = workflowProperties.Web.EnsureUser(((TaskActivity)e.Activity).Executor);
                int taskNo = ((TaskActivity)e.Activity).Data.TaskNo;
                // Уменьшим счетчик
                uncompletedTasks--;

                // Запишем информацию в историю WF
                workflowProperties.Workflow.CreateHistoryEvent((int)SPWorkflowHistoryEventType.WorkflowComment, 0, null, "Info", String.Format("Task #{0} finished by '{1}' with '{2}' status", taskNo, taskExecutor.Name, taskResult), string.Empty);
            }
        }


        /// <summary>
        /// Условие, при котором репликатор считается завершенным
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stageActivity_IsComplete(object sender, ConditionalEventArgs e)
        {
            // Если задачи закончились или отклонили, уходим
            e.Result = (uncompletedTasks <= 0);
        }


        /// <summary>
        /// Код, выполняемый при завершении работы репликатора
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stageActivity_Completed(object sender, EventArgs e)
        {
            workflowProperties.Workflow.CreateHistoryEvent((int)SPWorkflowHistoryEventType.WorkflowComment, 0, null, "Info", "Parallel approval finished", string.Empty);
        }

        private void onWorkflowActivated_Invoked(object sender, ExternalDataEventArgs e)
        {
            workflowProperties.Workflow.CreateHistoryEvent((int)SPWorkflowHistoryEventType.WorkflowComment, 0, null, "Info", "WF started", string.Empty);
        }


    }
}
